home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 423_01 / recio200 / design.txt < prev    next >
Encoding:
Text File  |  1994-04-15  |  13.3 KB  |  308 lines

  1.     Title: RECIO DESIGN AND DEVELOPMENT NOTES
  2. Copyright: (C) 1994 William Pierpoint
  3.   Version: 2.00
  4.      Date: April 15, 1994
  5.  
  6.  
  7.  
  8. 1.0 DATA STRUCTURES
  9.  
  10. 1.1 REC structure for each record stream
  11.  
  12.     * defined in recio.h.
  13.     * one static REC for recin (included in ROPEN_MAX count).
  14.     * allocate dynamic array of RECs dimensioned to ROPEN_MAX-NREC in ropen().
  15.     * Each REC has two associated buffers:
  16.       1) record string buffer containing current record;
  17.          allocate when first record read;
  18.          reallocate if record becomes larger.
  19.       2) field string buffer containing current field;
  20.          allocate when first field read;
  21.          reallocate if field becomes larger.
  22.     * deallocate dynamic RECs and associated buffers in rclose() and
  23.       rcloseall() if all record streams closed; deallocate associated
  24.       buffers for recin with an exit function registered with atexit().
  25.  
  26.  
  27. 1.2 REC r_flags assignments
  28.  
  29.     Bit        Description
  30.    -----    -------------------------------------------------------------
  31.      0        If clear, colno start at 0; if set, colno start at 1
  32.      1      if clear, read mode; if set, write/append mode
  33.     2-6     Reserved
  34.      7        If clear, EOF not reached; if set, EOF reached
  35.     8-11    If clear, no error; else, rerror number
  36.    12-15    if clear, no warning; else, rwarning number
  37.  
  38.  
  39. 1.3 Accessing REC Members and Associated Buffers
  40.  
  41.     How do I
  42.     * access the name of the record stream?           rnames()
  43.     * access the current context number?              rcxtno()
  44.     * access the current record number?               rrecno()
  45.     * access the current field number?                rfldno()
  46.     * access the current column number?               rcolno()
  47.     * access the record string buffer?                rrecs()
  48.     * access the field string buffer?                 rflds()
  49.     * determine if column numbers start at 0 or 1     rbegcolno()
  50.     * determine if there are more records left?       reof()
  51.     * determine if there is an error on the stream?   rerror()
  52.     * determine if there is a warning on the stream?  rwarning()
  53.     * access the error message for the stream?        rerrstr()
  54.     * force an error on a record stream?              rseterr()
  55.     * clear an error on a record stream?              rclearerr()
  56.     * increase the size of the record string buffer?  rsetrecsiz()
  57.     * increase the size of the field string buffer?   rsetfldsiz()
  58.     * replace the data in the field string buffer?    rsetfldstr()
  59.     * set the field delimiter character?              rsetfldch()
  60.     * set the text delimiter character?               rsettxtch()
  61.     * set the context number?                         rsetcxtno()
  62.     * set column numbering to start at 0 or 1?        rsetbegcolno()
  63.     * check for incoming empty data strings?          rsetstrattr()
  64.  
  65.  
  66.  
  67. 2.0 CODE STRUCTURES
  68.  
  69. 2.1 Functional Decomposition
  70.  
  71.                                  ╔═════════╗
  72.                                  ║ recio.c ║
  73.                                  ╚═╤══╤══╤═╝
  74.                                    │  │  │
  75.               ╔════════╗     input │  │  │ output   ╔════════╗
  76.               ║ rget.c ╟───────────┘  │  └──────────╢ rput.c ║
  77.        char   ╚═╤════╤═╝ column       │      char   ╚═╤════╤═╝ column
  78.      delimited  │    │  delimited     │    delimited  │    │  delimited
  79.     ╔═════════╗ │    │ ╔══════════╗   │   ╔═════════╗ │    │ ╔══════════╗
  80.     ║ rgets.c ╟─┤    ├─╢ rcgets.c ║   │   ║ rputs.c ╟─┤    ├─╢ rcputs.c ║
  81.     ╚═════════╝ │    │ ╚══════════╝   │   ╚═════════╝ │    │ ╚══════════╝
  82.                 │    │                │               │    │
  83.     ╔═════════╗ │    │ ╔══════════╗   │   ╔═════════╗ │    │ ╔══════════╗
  84.     ║ rgetf.c ╟─┤    ├─╢ rcgetf.c ║   │   ║ rputf.c ╟─┤    ├─╢ rcputf.c ║
  85.     ╚═════════╝ │    │ ╚══════════╝   │   ╚═════════╝ │    │ ╚══════════╝
  86.                 │    │                │               │    │
  87.     ╔═════════╗ │    │ ╔══════════╗   │   ╔═════════╗ │    │ ╔══════════╗
  88.     ║ rbget.c ╟─┘    └─╢ rcbget.c ║   │   ║ rbput.c ╟─┘    └─╢ rcbput.c ║
  89.     ╚═════════╝        ╚══════════╝   │   ╚═════════╝        ╚══════════╝
  90.                                       │
  91.                        ╔══════════╗   │   ╔═════════╗        ╔══════════╗
  92.                        ║ rwarn.c  ╟───┴───╢ rerr.c  ╟────────╢  rfix.c  ║
  93.                        ╚══════════╝       ╚═════════╝        ╚══════════╝
  94.  
  95.  
  96. 2.2 Callback Error Function Skeleton
  97.  
  98.     if valid record pointer [risvalid(rp)]
  99.         if past end of file [reof(rp)]  (if reof test removed, past EOF will
  100.         else [error number set]           become R_EMISDAT or R_WEMPSTR)
  101.             switch error number [rerror(rp)]
  102.             case read data errors [R_ERANGE || R_EINVDAT || R_EMISDAT]
  103.             case write data errors [R_ENOPUT || R_EWIDTH]
  104.                 switch context number [rcxtno(rp)]
  105.                 case RECIN
  106.                     switch field number [rfldno(rp)]
  107.                     case 1 (first field read)
  108.                     case 2 (second field read)
  109.                     ...
  110.                     endcase
  111.                 ...
  112.                 default [missing or unknown context number]
  113.                 endcase
  114.             case out of memory [R_ENOMEM]
  115.             case fatal errors [R_EINVAL || R_EINVMOD]
  116.             default [possibly set by application with rseterr()]
  117.             endcase
  118.         endif
  119.     else [invalid record pointer]
  120.         switch error number [errno]
  121.         case out of memory [ENOMEM]
  122.         case out of record or file pointers [EMFILE]
  123.         case permission denied [EACCES]
  124.         case fatal errors [EINVAL]
  125.         default [possibly set by application with rseterr()]
  126.         endcase
  127.     endif
  128.  
  129.  
  130. 2.3 Callback Warning Function Skeleton
  131.  
  132.     if valid record pointer [risvalid(rp)]
  133.         switch warning number [rwarning(rp)]
  134.         case data string empty [R_WEMPSTR]
  135.         case atexit fn full [R_WNOREG]
  136.         case data too wide for columns [R_WWIDTH]
  137.         default [possibly set by application with rsetwarn()]
  138.         endcase
  139.     endif
  140.  
  141. 2.4 Classes of Field Functions
  142.  
  143.     There are eight classes of field functions:
  144.  
  145.     rget   - input character delimited field, base 10 if numeric field
  146.     rbget  - input numeric character delimited field, base 2-36
  147.     rcget  - input column delimited field, base 10 if numeric field
  148.     rcbget - input numeric column delimited field, base 2-36
  149.     rput   - output character delimited field, base 10 if numeric field
  150.     rbput  - output numeric character delimited field, base 2-36
  151.     rcput  - output column delimited field, base 10 if numeric field
  152.     rcbput - output numeric column delimited field, base 2-36
  153.  
  154.  
  155. 2.5 How to Define and Declare New Numeric Field Functions
  156.  
  157.     You can define a new function to input or output numeric data using one 
  158.     of these macros:
  159.  
  160.     macro:         macro defined in:    define new function in:
  161.     -----------    -----------------    -----------------------
  162.     rget_fn()      _rgetf.h             rgetf.c
  163.     rbget_fn()     _rbget.h             rbget.c
  164.     rcget_fn()     _rcgetf.h            rcgetf.c
  165.     rcbget_fn()    _rcbget.h            rcbget.c
  166.     rput_fn()      _rputf.h             rputf.c
  167.     rbput_fn()     _rbput.h             rbput.c
  168.     rcput_fn()     _rcputf.h            rcputf.c
  169.     rcbput_fn()    _rcbput.h            rcbput.c
  170.  
  171.     macro:         declare new function in recio.h as:
  172.     -----------    ---------------------------------------------------------
  173.     rget_fn()      rget?(REC *rp);
  174.     rbget_fn()     rbget?(REC *rp, int base);
  175.     rcget_fn()     rcget?(REC *rp, size_t begcol, size_t endcol);
  176.     rcbget_fn()    rcbget?(REC *rp, size_t begcol, size_t endcol, int base);
  177.     rput_fn()      rput?(REC *rp, datatype);
  178.     rbput_fn()     rbput?(REC *rp, int base, datatype);
  179.     rcput_fn()     rcput?(REC *rp, size_t begcol, size_t endcol, datatype);
  180.     rcbput_fn()    rcbput?(REC *rp, size_t begcol, size_t endcol, int base,
  181.                     datatype);
  182.                    where ? is one or more new unique letters
  183.                      and datatype is the data type (e.g. integer)
  184.  
  185.     rbget_fn and rcbget_fn define integral number input functions
  186.     -----------------------------------------------------------------------
  187.     fn_type        defined function return type
  188.     fn_name        defined function name
  189.     fn_err         defined function error return value
  190.     cv_type        conversion function return type
  191.     cv_name        conversion function name
  192.     fn_min         inclusive valid minimum value (overflow limit)
  193.     fn_max         inclusive valid maximum value (overflow limit)
  194.  
  195.     rget_fn and rcget_fn define floating point input functions
  196.     -----------------------------------------------------------------------
  197.     fn_type        defined function return type
  198.     fn_name        defined function name
  199.     fn_err         defined function error return value
  200.     cv_type        conversion function return type
  201.     cv_name        conversion function name
  202.     fn_negmin      inclusive valid negative minimum value (overflow limit)
  203.     fn_negmax      inclusive valid negative maximum value (underflow limit)
  204.     fn_posmin      inclusive valid positive minimum value (underflow limit)
  205.     fn_posmax      inclusive valid positive maximum value (overflow limit)
  206.  
  207.     rbput_fn and rcbput_fn define integral number output functions
  208.     -----------------------------------------------------------------------
  209.     fn_type        defined function data type
  210.     fn_name        defined function name
  211.     cv_type        conversion function cast
  212.     cv_name        conversion function name
  213.  
  214.     rput_fn and rcput_fn define floating point output functions
  215.     -----------------------------------------------------------------------
  216.     fn_type        defined function data type
  217.     fn_name        defined function name
  218.     cv_type        conversion function cast
  219.     cv_name        conversion function name
  220.     cv_dig         conversion function number of significant digits
  221.  
  222.     The commonly used conversion functions are:
  223.  
  224.     name:          return type:
  225.     -------        --------------------------------------------------------
  226.     strtol         long
  227.     strtoul        unsigned long
  228.     str2ul         unsigned long (tests for invalid negative numbers)
  229.     strtod         double
  230.     str2c          character
  231.  
  232.     name:          cast:
  233.     ------         ----------------
  234.     itoa           int
  235.     ltoa           long
  236.     ultoa          unsigned long
  237.  
  238.     portability note: functions starting with str are part of ansi-c
  239.                       reserved namespace
  240.  
  241.     Example: suppose you want to define a function rgetb() that gets a
  242.              boolean value (unsigned char) and generates an ERANGE error
  243.              if the value is not 0 or 1:
  244.  
  245.      /* definition to add to rget.c */
  246.      rget_fn(unsigned char, rgetb, 0, long, strtol, 0,  1)
  247.  
  248.      /* declaration to add to recio.h */
  249.      rgetb(REC *rp);
  250.  
  251.      --OR to generate an EINVDAT error if the value is not 0 or 1--
  252.  
  253.      /* definition to add to rbget.c */
  254.      rbget_fn(unsigned char, rbgetb, 0, unsigned long, str2ul, 0,  1)
  255.  
  256.      /* declaration to add to recio.h */
  257.      rbgetb(REC *rp, int base);
  258.  
  259.      /* macro to add to recio.h */
  260.      #define rgetb(rp) (rbgetb((rp), 2))
  261.  
  262.  
  263.  
  264. 3.0 DEVELOPMENT NOTES
  265.  
  266. 3.1 fgets (Microsoft C 5.1)
  267.  
  268. Previous notes of mine indicate that Microsoft's fgets function does not
  269. work correctly when it reads a line of text that consists of only a newline.
  270. However this can be worked around by first setting the string buffer to an
  271. empty string.  If you plan on retaining the newline, you will need to test
  272. this further.  The fgets function is used twice in the rgetrec function.
  273. If porting to Microsoft C, you may need to implement this fix in recio.c:
  274.  
  275.      *rrecs(rp) = '\0';  /* just prior to the first fgets (added v1.20) */
  276.      *str = '\0';        /* just prior to the second fgets */
  277.  
  278.  
  279. 3.2 fopen (Borland C 3.1)
  280.  
  281. fopen() calls __openfp() calls open().  Borland's "Library Reference"
  282. documents error numbers for open(), but not for fopen().  These error
  283. numbers are ENOENT, EMFILE, EACCES, and EINVACC.  Because ropen() screens
  284. the access code, the EINVACC error will not occur from the recio library.
  285.  
  286.  
  287. 3.3 strtol & strtoul (Borland C 3.1)
  288.  
  289. These functions stop consuming input once they overflow, setting ERANGE.
  290. Hence endptr can point into the middle of a sequence of valid characters
  291. having the expected form as given in ANSI X3.159-1989, Sections 4.10.1.5
  292. and 4.10.1.6.  IMHO this characteristic is not in conformance with the
  293. ANSI standard as endptr should only point to the first unrecognized
  294. character or to the terminating null character.  Borland's strtod does
  295. not have this problem.
  296.  
  297. Note that ANSI X3.159-1989 Section 4.10.1.6 allows strtoul (unsigned
  298. long) to have an optional negative sign.  A negative unsigned long?
  299. Borland 3.1 strtoul converts a negative long to an unsigned number
  300. without error.  But I prefer to trap any negative numbers input to
  301. unsigned fields.  So str2ul is a wrapper function for strtoul that
  302. first tests for a negative number and if one is found, flags the data
  303. as invalid and returns zero.
  304.  
  305. The test suite includes -0 as a data value.  The strtol function traps
  306. this as an ERANGE error and returns the overflow limit.  The rfixi and
  307. rfixl functions substitute zero.
  308.